package com.hooker.plugins;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;

import com.hooker.base.BaseXposedLoader;
import com.hooker.common.ReflectA;

import org.json.JSONObject;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class ByteDanceHook extends BaseXposedLoader {
    public ByteDanceHook(Context context, XC_LoadPackage.LoadPackageParam loadParams) {
        super(context, loadParams);
    }

    @Override
    public void hook(Object... calls) {
        log("hook " + getClass().getName());
        log("hook ~~~");
    }

    private Intent intent;

    @Override
    public void hook(final Context context, final XC_LoadPackage.LoadPackageParam loadParams) {
        super.hook(context, loadParams);
        hookAllConstructor("dalvik.system.BaseDexClassLoader", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                log("BaseDexClassLoader " + Arrays.toString(param.args));
                super.afterHookedMethod(param);
                hookbg(((ClassLoader) param.thisObject));
                XposedHelpers.findAndHookMethod("com.ss.android.socialbase.appdownloader.DownloadHandlerService", ((ClassLoader) param.thisObject), "a", Intent.class, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        super.beforeHookedMethod(param);
                        log("DownloadHandlerService a:" + Arrays.toString(param.args));
                    }
                });
                log("hook DownloadHandlerService");
//                if (param.args[0] instanceof String) {
//                    String arg = (String) param.args[0];
//                    if (arg.contains("bytedance")) {
//                        ClassLoader classLoader = ((ClassLoader) param.thisObject);
//
//                        XposedHelpers.findAndHookMethod("com.bytedance.sdk.openadsdk.core.a", classLoader, "a", String.class, String.class, new XC_MethodHook() {
//                            @Override
//                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                                super.beforeHookedMethod(param);
//                                String s = param.args[0].toString();
//                                for (int i = 0; i < s.length();) {
//                                    log("加密前数据::" + s.substring(i,Math.min(i+1024,s.length())));
//                                    i += 1024;
//                                }
//                            }
//                        });
//
//
//
//                        hookMethod("com.bytedance.sdk.adnet.core.Request",classLoader, "getBody", new XC_MethodHook() {
//                            @Override
//                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                                super.afterHookedMethod(param);
//                                byte[] result = ((byte[]) param.getResult());
//                                String s = new String(result);
//
//                                Method getUrl = param.thisObject.getClass().getMethod("getUrl");
//                                getUrl.setAccessible(true);
//                                Object url = getUrl.invoke(param.thisObject);
//
//                                for (int i = 0; i < s.length();) {
//                                    log("Request body:"+url+" : " + s.substring(i,Math.min(i+1024,s.length())));
//                                    i += 1024;
//                                }
//                            }
//                        });
//
//                        hookMethod("com.bytedance.sdk.adnet.core.Request",classLoader, "getBody", new XC_MethodHook() {
//                            @Override
//                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                                super.afterHookedMethod(param);
//                                byte[] result = ((byte[]) param.getResult());
//                                String s = new String(result);
//
//                                Method getUrl = param.thisObject.getClass().getMethod("getUrl");
//                                getUrl.setAccessible(true);
//                                Object url = getUrl.invoke(param.thisObject);
//
//                                for (int i = 0; i < s.length();) {
//                                    log("Request body:"+url+" : " + s.substring(i,Math.min(i+1024,s.length())));
//                                    i += 1024;
//                                }
//                            }
//                        });
//
//                    }
//                }
            }
        });

//        hookMethod(JSONObject.class, "put", String.class, Object.class, new XC_MethodHook() {
//            @Override
//            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//                super.beforeHookedMethod(param);
//                String key = ((String) param.args[0]);
//                Object arg = param.args[1];
//                if ("package_name".equals(key) && "com.sdk.ebad".equals(arg)) {
//                    log("JSON PUT key:" + key + " value:" + arg);
//                    for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
//                        log("JSON PUT package_name " + stackTraceElement);
//                    }
//                }
//
//                if ("app_version".equals(key) && "1.4-20200615".equals(arg)) {
//                    log("JSON PUT key:" + key + " value:" + arg);
//                    for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
//                        log("JSON PUT app_version " + stackTraceElement);
//                    }
//                }
//
//                if ("show_time".equals(key)) {
//                    log("JSON PUT key show_time value:" + param.args[1]);
//                    for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
//                        log("JSON PUT key show_time " + stackTraceElement);
//                    }
//                }
//
//            }
//        });
//        log("hook json");

        XposedBridge.hookAllMethods(NotificationManager.class, "notify", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);
                log("NotificationManager notify:" + Arrays.toString(param.args));
                for (Object arg : param.args) {
                    if (arg instanceof Notification) {
                        Notification arg1 = (Notification) arg;
                        PendingIntent contentIntent = arg1.contentIntent;
                        log("contentIntent:" + contentIntent);
                    }
                    if (arg.getClass() == int.class) {
                        int notifyId = (int) arg;

                    }
                }
            }
        });

        XposedBridge.hookAllMethods(PendingIntent.class, "getService", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);
                log("PendingIntent getService:" + Arrays.toString(param.args));
                for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
                    log("PendingIntent getService :" + stackTraceElement);
                }
                for (Object arg : param.args) {
                    if (arg instanceof Intent) {
                        Intent arg1 = (Intent) arg;
                        if ("android.ss.intent.action.DOWNLOAD_CLICK".equals(arg1.getAction())) {
//                            int extra_click_download_ids = ((Intent) arg).getIntExtra("extra_click_download_ids", 0);
//                            int extra_click_download_type = ((Intent) arg).getIntExtra("extra_click_download_type", 0);
//                            String notification_name = ((Intent) arg).getStringExtra("notification_name");
//                            final Intent intentPasue = new Intent(context,loadParams.classLoader.loadClass("com.ss.android.socialbase.appdownloader.DownloadHandlerService"));
//                            intentPasue.setAction("android.ss.intent.action.DOWNLOAD_CLICK");
//                            intentPasue.putExtra("notification_name", notification_name);
//                            intentPasue.putExtra("extra_click_download_ids", extra_click_download_ids);
//                            intentPasue.putExtra("extra_click_download_type", extra_click_download_type);
//                            intentPasue.putExtra("extra_from_notification",true);
////                            bnds=[889,244][1033,323]
//                            intentPasue.setSourceBounds(new Rect(889,244,1033,323));
//                            log("extra_click_download_ids:" + extra_click_download_ids);
//                            log("extra_click_download_type:" + extra_click_download_type);
//                            intent = intentPasue;
//                            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
//                                @Override
//                                public void run() {
//                                    log("暂停任务");
//                                    context.startService(intentPasue);
//                                }
//                            },2500);

//                            final Intent intentPasue1 = new Intent(context,loadParams.classLoader.loadClass("com.ss.android.socialbase.appdownloader.DownloadHandlerService"));
//                            intentPasue1.setAction("android.ss.intent.action.DOWNLOAD_DELETE");
//                            intentPasue1.putExtra("notification_name", notification_name);
//                            intentPasue1.putExtra("extra_click_download_ids", extra_click_download_ids);
//                            intentPasue1.putExtra("extra_click_download_type", extra_click_download_type);
//
//
//                            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
//                                @Override
//                                public void run() {
//                                    log("暂停任务");
//                                    context.startService(intentPasue1);
//                                }
//                            },3000);
                        }
                    }
                }
            }
        });
        log("PendingIntent getService");

        XposedHelpers.findAndHookMethod("com.ss.android.socialbase.appdownloader.DownloadHandlerService", loadParams.classLoader, "a", Intent.class, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);
                Bundle extras = ((Intent) param.args[0]).getExtras();
                extras.getInt("extra_click_download_ids");
                Bundle mExtras = ReflectA.get(((Intent) param.args[0]), "mExtras");
                Object mMap = ReflectA.get(mExtras, "mMap");

                log("DownloadHandlerService a  mMap:"+mMap);
                log("DownloadHandlerService a  Bundle:"+extras);
                log("DownloadHandlerService a " + Arrays.toString(param.args));
            }
        });

        log("DownloadHandlerService a");

//
//        hookMethod(Log.class, "d", String.class, String.class, new XC_MethodHook() {
//            @Override
//            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//                super.beforeHookedMethod(param);
//                Object arg = param.args[0];
//                if(arg.equals("VNetLog")){
//                    if(param.args[1]!=null && param.args[1].toString().contains("get_ads")){
//                        for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
//                            log("get_ads :"+stackTraceElement);
//                        }
//                    }
//                }
//            }
//        });
//
//        hookMethod(URL.class, "openConnection", new XC_MethodHook() {
//            @Override
//            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//                super.beforeHookedMethod(param);
//                log("openConnection :"+param.thisObject);
//            }
//        });
//
//        hookMethod(URL.class, "openConnection", java.net.Proxy.class,new XC_MethodHook() {
//            @Override
//            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//                super.beforeHookedMethod(param);
//                log("openConnection Proxy :"+param.thisObject);
//            }
//        });
//
//        hookMethod(JSONObject.class, "optJSONArray", String.class, new XC_MethodHook() {
//            @Override
//            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                super.afterHookedMethod(param);
//                if (param.args[0].toString().equals("creatives")) {
//                    JSONArray result = (JSONArray) param.getResult();
//                }
//            }
//        });
//
//        hookMethod("com.bytedance.sdk.adnet.core.Request",loadParams.classLoader, "getBody", new XC_MethodHook() {
//            @Override
//            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                super.afterHookedMethod(param);
//                byte[] result = ((byte[]) param.getResult());
//                String s = new String(result);
//
//                Method getUrl = param.thisObject.getClass().getMethod("getUrl");
//                getUrl.setAccessible(true);
//                Object url = getUrl.invoke(param.thisObject);
//
//                for (int i = 0; i < s.length();) {
//                    log("Request body:"+url+" : " + s.substring(i,Math.min(i+1024,s.length())));
//                    i += 1024;
//                }
//            }
//        });


//        hookAllConstructor("com.bytedance.sdk.adnet.core.Request", new XC_MethodHook() {
//            @Override
//            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                super.afterHookedMethod(param);
////                log("Request Constructor "+param.args.length);
//                if(param.args.length == 3){
//
//                    Object thisObject = param.thisObject;
//
//                    //url
//                    Method getUrl = thisObject.getClass().getMethod("getUrl");
//                    getUrl.setAccessible(true);
//                    String url = (String)getUrl.invoke(thisObject);
//                    if(url.contains("ug.snssdk.com")){
//                        log("ug.snssdk.com");
//                        log("ug.snssdk.com "+Arrays.toString(param.args));
//                        for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
//                            log("ug.snssdk.com "+stackTraceElement);
//                        }
//                        //                    //header
//                    Method getHeaders = thisObject.getClass().getMethod("getHeaders");
//                    getHeaders.setAccessible(true);
//                    Map<String, String> header = ((Map<String, String>) getHeaders.invoke(thisObject));
//
//                    //body
//                    Method getBody = thisObject.getClass().getMethod("getBody");
//                    getBody.setAccessible(true);
//                    byte[] body = (byte[]) getBody.invoke(thisObject);
//
//                    //getPostBody
//                    Method getPostBody = thisObject.getClass().getMethod("getPostBody");
//                    getPostBody.setAccessible(true);
//                    byte[] postBody = (byte[]) getBody.invoke(thisObject);
//
//                    log("Request Constructor url :"+url);
//                    log("Request Constructor Request "+thisObject.getClass().getName());
//                    log("Request Constructor header :"+header);
//                    if(body!=null && body.length>0) {
//                        log("Request Constructor body :" + new String(body));
//                    }
//
//                    if(postBody!=null && postBody.length>0) {
//                        log("Request Constructor postBody :" + new String(postBody));
//                    }
//
//                    }
//
//                }
//            }
//        });

        hookAllConstructor("com.bytedance.sdk.adnet.b.j", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                Object thisObject = param.thisObject;
                //url
                Method getUrl = thisObject.getClass().getMethod("getUrl");
                getUrl.setAccessible(true);
                String url = (String) getUrl.invoke(thisObject);

                    //                    //header
                    Method getHeaders = thisObject.getClass().getMethod("getHeaders");
                    getHeaders.setAccessible(true);
                    Map<String, String> header = ((Map<String, String>) getHeaders.invoke(thisObject));

                    //body
                    Method getBody = thisObject.getClass().getMethod("getBody");
                    getBody.setAccessible(true);
                    byte[] body = (byte[]) getBody.invoke(thisObject);

                    //getPostBody
                    Method getPostBody = thisObject.getClass().getMethod("getPostBody");
                    getPostBody.setAccessible(true);
                    byte[] postBody = (byte[]) getBody.invoke(thisObject);

                    log("Request Constructor url :" + url);
                    log("Request Constructor Request " + thisObject.getClass().getName());
                    log("Request Constructor header :" + header);
                    if (body != null && body.length > 0) {
                        log("Request Constructor body :" + new String(body));
                    }

                    if (postBody != null && postBody.length > 0) {
                        log("Request Constructor postBody :" + new String(postBody));
                    }

            }
        });

        hookbg(loadParams.classLoader);

    }

    private void hookbg(final ClassLoader classLoader) {
        try {
            XposedBridge.hookAllConstructors(classLoader.loadClass("com.bytedance.sdk.adnet.b.g"), new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);

                    Object thisObject = param.thisObject;

                    //url
                    Method getUrl = thisObject.getClass().getMethod("getUrl");
                    getUrl.setAccessible(true);
                    String url = (String) getUrl.invoke(thisObject);

                    //header
                    Method getHeaders = thisObject.getClass().getMethod("getHeaders");
                    getHeaders.setAccessible(true);
                    Map<String, String> header = ((Map<String, String>) getHeaders.invoke(thisObject));

                    String body = ((String) param.args[2]);
                    if (thisObject.getClass().getName().equals("com.bytedance.sdk.openadsdk.core.q$3")) {
                        //                    com.bytedance.sdk.openadsdk.core.b.b();
                        Class<?> classB = classLoader.loadClass("com.bytedance.sdk.openadsdk.core.b");
                        Method b = classB.getDeclaredMethod("b");
                        b.setAccessible(true);
                        String key = (String) b.invoke(null);
                        //                    com.bytedance.sdk.openadsdk.core.a.b
                        Class<?> classab = classLoader.loadClass("com.bytedance.sdk.openadsdk.core.a");
                        Method decoderMethod = classab.getDeclaredMethod("b", String.class, String.class);
                        decoderMethod.setAccessible(true);
                        body = (String) decoderMethod.invoke(null, body, key);

                    } else {
                        body = decoderJson(body, classLoader);
                    }

                    if (url.contains("dig.bdurl.net")) {
                        for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
                            log("dig.bdurl.net " + stackTraceElement);
                        }
                    }


                    log("Request Constructor url :" + url);
                    log("Request Constructor Request " + thisObject.getClass().getName());
                    log("Request Constructor header :" + header);
                    log("Request Constructor body :" + body);
                    if (body.contains("toolType")) {
                        log("Request Constructor ");
                    }
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private String decoderJson(String jsonObjectStr, ClassLoader classLoader) {
        try {
            JSONObject jsonObject = new JSONObject(jsonObjectStr);
            Class<?> qClass = classLoader.loadClass("com.bytedance.sdk.openadsdk.core.q");
            Constructor<?> declaredConstructor = qClass.getDeclaredConstructor(Context.class);
            declaredConstructor.setAccessible(true);
            Object q = declaredConstructor.newInstance(context);
            Method e1 = qClass.getDeclaredMethod("e", JSONObject.class);
            e1.setAccessible(true);
            JSONObject e = (JSONObject) e1.invoke(q, jsonObject);
            return e.toString();
        } catch (Throwable e) {

        }
        return jsonObjectStr;
    }
}
